#!/usr/bin/env python3
# -*- coding: utf8 -*-

"""repo_git_update 用来更新repo仓库(由SOURCE指定)的patch, 并生成patch到TARGET目录中
Usage:
	repo_git_update.py -h | --help
	repo_git_update.py SOURCE TARGET PEFIX

Args:
	SOURCE  源目录，包含要提取patch的git仓库
	TARGET  目标目录，为要存放patch的目录
	RPEFIX  patch修复前缀

Options:
	-h --help  show this message

"""
from docopt import docopt
from subprocess import run, call, check_output, CalledProcessError
from datetime import datetime
from pathlib import Path
import os
from contextlib import contextmanager
import random
import string

@contextmanager
def cw(nws):
    """ 方便进行路径管理 """
    old = os.path.abspath('.')
    try:
        os.chdir(nws)
        yield
    finally:
        os.chdir(old)


def gen_patch(source, target, last_cid=None):
    ''' 从last_cid中指定的commit id值，使用format-patch提取patch到target中
    @target @source should both absolute path'''
    out = None
    target = os.path.abspath(target) # convert it to absolute
    with cw(source):
        if not os.path.isdir('.git'):
            raise ValueError(f'{souorce} do not contain git')
        cur_cid = check_output('git log --pretty=format:%h -n1', shell=True).decode('utf8')
        info = check_output('git log --pretty=format:%ad-%h --date=format:%Y%m%d -n1', shell=True).decode('utf8')
        out = f'{target}/{info}'
        call(f'mkdir -p {out}', shell=True)
        ret = call(f'git format-patch -o {out} {last_cid}', shell=True)
        print(f'ret={ret}')
    return out


def fix_repo_file(fn, fix='', fout=''):
    """ 将从repo中导出的patch转换成大git能识别的文件
    fn 要修复的文件路径
    fix 要增加的前缀
    fout 输出文件路径
    """
    with open(fn) as fp:
        lines = fp.readlines()
    leaders = ('--- a', '+++ b')
    for i, line in enumerate(lines):
        for leader in leaders:
            if line.startswith(leader):
                lines[i] = f'{leader}/{fix}{line[len(leader):]}'
        if line.startswith('diff --git'):
            lines[i] = line.replace(' a/', f' a/{fix}/').replace(' b/', f' b/{fix}/')
    fout = fout if fout else f'{fn}.fix'
    with open(fout, 'w') as fp:
        fp.write(''.join(lines))


def fix_repo(folder, fix=''):
    """ 修改folder目录中的全部patch文件，并输出到$(folder)-fix目录中
    """
    folder = Path(folder)
    out_folder = folder/'fixed'
    if not out_folder.exists():
        out_folder.mkdir()
    for f in os.listdir(folder):
        if f == 'fixed': continue
        print(f)
        fix_repo_file(folder/f, fix, out_folder/f)

def get_last_cid(target):
    """ 获取目录中最新文件对应的 commit id值， target目录中的子目录应当是: yyyymmdd-cid 格式"""
    fs = os.listdir(target)
    return sorted(fs, key=lambda s:s.split('-')[0], reverse=True)[0].split('-')[1]

def run(source ,target, prefix):
    # find last_cid, 从目标路径中获取最新的patch
    cid = get_last_cid(target)
    # call gen_patch 根本目标中的提交，在源代码中找出新的提交
    out = gen_patch(source, target, cid)
    # call fix_repo
    fix_repo(out)
    pass

def main(args):
	print(args)
	run(args['SOURCE'], args['TARGET'], args['PEFIX'])

if __name__ == '__main__':
	main(docopt(__doc__))